﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using monitor_2_DBwork;
using ServerLib;
using Timer = System.Threading.Timer;

namespace monitor_server_2
{
    public partial class ServerLog : Form
    {
        private delegate void UpdateListDelegate();
        //private const string ServerLogLastRecordsCountOptionName = "ServerLogLastRecordsCount";
        private bool _success;
        private bool _ascSort;
        private int _preColumn = 5;
        private const int TabControlHeightFilter = 145;
        private const int TabControlHeightCount = 57;
        private readonly string _boxChecked = Main.Rm.GetString("ExactCheckBoxTitle");
        private readonly string _boxUnchecked = Main.Rm.GetString("LikeCheckBoxTitle");
        private const string AutoUpdateServerLogOption = "AutoUpdateServerLogListEnabled";
        private Timer _listUpdateTimer;

        public ServerLog()
        {
            InitializeComponent();
            AllowTransparency = true;
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Close();
        }

        private void ServerLog_Load(object sender, EventArgs e)
        {
            _listUpdateTimer = new Timer(state =>
                {
                    _listUpdateTimer.Change(Timeout.Infinite, Timeout.Infinite);
                    try
                    {
                        tabControl.Invoke(new UpdateListDelegate(RefreshList));
                    }
                    catch (InvalidOperationException)
                    {
                        return;
                    }
                    //RefreshList();
                    _listUpdateTimer.Change(1000, Timeout.Infinite);
                });
            autoUpdateBox.Text = Main.Rm.GetString("AutoUpdate");
            amountLabel.Text = Main.Rm.GetString("RecordsAmount") + ':';
            Text = Main.Rm.GetString("ServerLog");
            _checkBoxTip.IsBalloon = false;
            
            //Автообновление списка
            var logupd = DBwork.GetOptionValue(AutoUpdateServerLogOption);
            if (logupd.Contains("can not get value"))
            {
                logupd = "false";
                var check = DBwork.AddOrSetOptionValue(AutoUpdateServerLogOption, logupd);
                if (check != "ok")
                    MessageBox.Show(check, Main.Rm.GetString("Warning"), MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
            bool lu;
            if (!bool.TryParse(logupd, out lu))
                MessageBox.Show(Main.Rm.GetString("CanNotResolveParameter") + ": " + AutoUpdateServerLogOption);
            else
            {
                autoUpdateBox.Checked = lu;
            }

            //DBwork.AddOrSetOptionValue("AutoUpdateServerLog", "");

            //Меню
            menuToolStripMenuItem.Text = Main.Rm.GetString("Menu");
            refreshToolStripMenuItem.Text = Main.Rm.GetString("Refresh");
            refreshToolStripMenuItem.Image = (Image)Main.Rm.GetObject("refresh_16");
            exitToolStripMenuItem.Text = Main.Rm.GetString("Close");
            exitToolStripMenuItem.Image = (Image) Main.Rm.GetObject("exit_16");

            //Список
            serverLogList.View = View.Details;
            serverLogList.GridLines = true;
            serverLogList.HeaderStyle = ColumnHeaderStyle.Clickable;
            serverLogList.FullRowSelect = true;

            //Получить значение количества последних записей
            countValue.Text = GetCount();

            //Фильтр
            CountTabActivated();
            lastCountLabel.Text = Main.Rm.GetString("InputValue");
            var imlist = new ImageList();
            imlist.Images.Add((Image) Main.Rm.GetObject("counter_16"));
            imlist.Images.Add((Image)Main.Rm.GetObject("xmag_16"));
            tabControl.ImageList = imlist;
            countTabPage.Text = Main.Rm.GetString("RecordsCount");
            countTabPage.ImageIndex = 0;
            filterTabPage.Text = Main.Rm.GetString("Filter");
            filterTabPage.ImageIndex = 1;
            categoryLabel.Text = Main.Rm.GetString("Category");
            accessLabel.Text = Main.Rm.GetString("Access");
            regionLabel.Text = Main.Rm.GetString("Region");
            userLabel.Text = Main.Rm.GetString("UserName");
            eventLabel.Text = Main.Rm.GetString("Event");
            startTimeLabel.Text = Main.Rm.GetString("StartTime");
            endTimeLabel.Text = Main.Rm.GetString("EndTime");
            accessCheckedListBox.Items.Add("Администратор");
            accessCheckedListBox.Items.Add("Пользователь");
            categoryCheckedListBox.Items.Add("Клиенты");
            categoryCheckedListBox.Items.Add("Информация");
            categoryCheckedListBox.Items.Add("Предупреждения");
            userCheckBox.Text = Main.Rm.GetString("SearchConditionLike");
            regionCheckBox.Text = Main.Rm.GetString("SearchConditionLike");
            eventCheckBox.Text = Main.Rm.GetString("SearchConditionLike");
            startDateTimePicker.Format = DateTimePickerFormat.Custom;
            startDateTimePicker.CustomFormat = @"dd MMMM yyyy - HH:mm:ss";
            startDateTimePicker.Value = DateTime.Now.Date;
            endDateTimePicker.Format = DateTimePickerFormat.Custom;
            endDateTimePicker.CustomFormat = @"dd MMMM yyyy - HH:mm:ss";
            endDateTimePicker.Value = DateTime.Now;
            serverLogList.ListViewItemSorter = new ListViewItemComparer(5, _ascSort);
            acceptButton.Text = Main.Rm.GetString("Accept") + " (F5)";

            //Cписка
            var slilist = new ImageList();

            slilist.Images.Add((Image)Main.Rm.GetObject("emptyImage"));
            slilist.Images.Add((Image)Main.Rm.GetObject("arrowup_16"));
            slilist.Images.Add((Image)Main.Rm.GetObject("arrowdown_16"));
            serverLogList.SmallImageList = slilist; 
            serverLogList.Columns.Add(Main.Rm.GetString("Login"));
            serverLogList.Columns[serverLogList.Columns.Count - 1].Width = 115;
            serverLogList.Columns[serverLogList.Columns.Count - 1].ImageIndex = 0;
            serverLogList.Columns.Add(Main.Rm.GetString("Access"));
            serverLogList.Columns[serverLogList.Columns.Count - 1].Width = 80;
            serverLogList.Columns[serverLogList.Columns.Count - 1].ImageIndex = 0;
            serverLogList.Columns.Add(Main.Rm.GetString("Region"));
            serverLogList.Columns[serverLogList.Columns.Count - 1].Width = 120;
            serverLogList.Columns[serverLogList.Columns.Count - 1].ImageIndex = 0;
            serverLogList.Columns.Add(Main.Rm.GetString("Category"));
            serverLogList.Columns[serverLogList.Columns.Count - 1].Width = 120;
            serverLogList.Columns[serverLogList.Columns.Count - 1].ImageIndex = 0;
            serverLogList.Columns.Add(Main.Rm.GetString("Event"));
            serverLogList.Columns[serverLogList.Columns.Count - 1].Width = 425;
            serverLogList.Columns[serverLogList.Columns.Count - 1].ImageIndex = 0;
            serverLogList.Columns.Add(Main.Rm.GetString("Date"));
            serverLogList.Columns[serverLogList.Columns.Count - 1].Width = 120;
            serverLogList.Columns[serverLogList.Columns.Count - 1].ImageIndex = 2;
            
            
                

#if DEBUG
            serverLogList.ColumnWidthChanged += serverLogList_ColumnWidthChanged;
#endif
            RefreshList();
        }

        private void FilterTabActivated()
        {
            var s = tabControl.Size;
            s.Height = TabControlHeightFilter;
            tabControl.Size = s;
            const int dif = TabControlHeightFilter - TabControlHeightCount;
            var l = serverLogList.Location;
            l.Y += dif;
            s = serverLogList.Size;
            s.Height -= dif;
            serverLogList.BeginUpdate();
            serverLogList.Location = l;
            serverLogList.Size = s;
            serverLogList.EndUpdate();
        }

        private void CountTabActivated()
        {
            var s = tabControl.Size;
            s.Height = TabControlHeightCount;
            tabControl.Size = s;
            const int dif = TabControlHeightFilter - TabControlHeightCount;
            var l = serverLogList.Location;
            l.Y -= dif;
            s = serverLogList.Size;
            s.Height += dif;
            serverLogList.BeginUpdate();
            serverLogList.Location = l;
            serverLogList.Size = s;
            serverLogList.EndUpdate();
            if (autoUpdateBox.CheckState == CheckState.Checked)
            {
                EnableTimer(_listUpdateTimer);
            }
            else if(autoUpdateBox.CheckState == CheckState.Unchecked)
            {
                DisableTimer(_listUpdateTimer);
            }
        }

#if DEBUG
        void serverLogList_ColumnWidthChanged(object sender, ColumnWidthChangedEventArgs e)
        {
            foreach (ColumnHeader column in ((ListView)sender).Columns)
            {
                Debug.Write(column.Width + "; ");
            }
            Debug.Write("Width: " + Width);
            Debug.WriteLine("Height: " + Height);
           
        }
#endif

        private void RefreshList()
        {
            string[] serverLogStr;
            string criteria = "";
            Dictionary<string, List<string>> pars = null; 
            DateTime dt1 = DateTime.Now;
            DateTime dt2 = DateTime.Now;
            int max = -1;
            switch (tabControl.SelectedIndex) 
            {
                case 0:     //count
                    dt1 = DateTime.Parse("1.01.2013");
                    dt2 = DateTime.Now;
                    max = int.Parse(countValue.Text);
                    criteria = " AND sl.Idcategory != 4 order by Date desc";
                    break;
                case 1:     //filter
                    criteria = MakeFilter(out dt1, out dt2, out pars);
                    break;
            }
            
            try
            {
                serverLogStr = DBwork.GetServerLogList(dt1, dt2, max, criteria, pars);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, Main.Rm.GetString("Error"), MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
                _success = false;
                return;
            }
            if (serverLogStr.Length < 1)
            {
                MessageBox.Show(Main.Rm.GetString("ReturnEmpty"), Main.Rm.GetString("Info"),MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }

            if (serverLogStr[0].Contains("err:"))
            {
                MessageBox.Show(serverLogStr[0].Substring(4), Main.Rm.GetString("Error"), MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
                _success = false;
                return;
            }
            var items = new ListViewItem[serverLogStr.Length];
            //serverLogList.BeginUpdate();
            //serverLogList.Items.Clear();
            int itc = 0;
            foreach (var str in serverLogStr)
            {
                if (str.Length < 1)
                    continue;
                string[] splitik = str.Split(';');
                var item = new ListViewItem(splitik[0]);
                for (int i = 1; i < splitik.Length; i++)
                {
                    item.SubItems.Add(splitik[i]);
                }
                items[itc++] = item;
            }
            try
            {
                if (items[0].SubItems[5].Text.Equals(serverLogList.Items[0].SubItems[5].Text))
                {
                    _success = true;
                    return;
                }
            }
            catch (Exception)
            {
            }
            serverLogList.BeginUpdate();
            serverLogList.Items.Clear();
            serverLogList.Items.AddRange(items);
            serverLogList.EndUpdate();
            _success = true;
            recordsAmountLabel.Text = items.Length.ToString();
        }

        private void ServerLog_Shown(object sender, EventArgs e)
        {
            if (!_success)
                Close();
        }

        private void tabControl_SelectedIndexChanged(object sender, EventArgs e)
        {
            var tc = (TabControl) sender;
            switch (tc.SelectedIndex)
            {
                case 0:
                    CountTabActivated();
                    break;
                case 1:
                    FilterTabActivated();
                    DisableTimer(_listUpdateTimer);
                    break;
            }
        }

        private string MakeFilter(out DateTime dt1, out DateTime dt2, out Dictionary<string, List<string>> pars)
        {
            pars = new Dictionary<string, List<string>>();

            var sb = new StringBuilder();
            var users = userTextBox.Lines;
            if (users.Length > 0)
            {
                if (userCheckBox.CheckState == CheckState.Unchecked)
                {
                    int i = 0;
                    foreach (var user in users)
                    {
                        var ulist = new List<string>();
                        if (i == 0)
                            sb.Append(" AND sl.Login LIKE :user" + i.ToString(CultureInfo.InvariantCulture));
                        else
                            sb.Append(" OR sl.Login LIKE :user" + i.ToString(CultureInfo.InvariantCulture));
                        ulist.Add("%" + user + "%");
                        pars.Add("user" + i.ToString(CultureInfo.InvariantCulture), ulist);
                        i++;
                    }
                }
                else
                {
                    sb.Append(" AND sl.Login IN (:users)");
                    var ulist = new List<string>();
                    foreach (var user in users)
                    {
                        ulist.Add(user);
                    }
                    pars.Add("users", ulist);
                }
            }
            var regions = regionTextBox.Lines;
            if (regions.Length > 0)
            {
                if (regionCheckBox.CheckState == CheckState.Unchecked)
                {
                    int i = 0;
                    foreach (var region in regions)
                    {
                        var rlist = new List<string>();
                        if (i == 0)
                            sb.Append(" AND sl.Oblast.Name LIKE :region" + i.ToString(CultureInfo.InvariantCulture));
                        else
                            sb.Append(" OR sl.Oblast.Name LIKE :region" + i.ToString(CultureInfo.InvariantCulture));
                        rlist.Add("%" + region + "%");
                        pars.Add("region" + i.ToString(CultureInfo.InvariantCulture), rlist);
                        i++;
                    }
                }
                else
                {
                    sb.Append(" AND sl.Oblast.Name IN (:regions)");
                    var rlist = new List<string>();
                    foreach (var region in regions)
                    {
                        rlist.Add(region);
                    }
                    pars.Add("regions", rlist);
                }
            }
            var events = eventTextBox.Lines;
            if (events.Length > 0)
            {
                if (eventCheckBox.CheckState == CheckState.Unchecked)
                {
                    int i = 0;
                    foreach (var ev in events)
                    {
                        var elist = new List<string>();
                        if (i == 0)
                            sb.Append(" AND sl.Name LIKE :ev" + i.ToString(CultureInfo.InvariantCulture));
                        else
                            sb.Append(" OR sl.Name LIKE :ev" + i.ToString(CultureInfo.InvariantCulture));
                        elist.Add("%" + ev + "%");
                        pars.Add("ev" + i.ToString(CultureInfo.InvariantCulture), elist);
                        i++;
                    }
                }
                else
                {
                    sb.Append(" AND sl.Name IN (:events)");
                    var elist = new List<string>();
                    foreach (var @event in events)
                    {
                        elist.Add(@event);
                    }
                    pars.Add("events", elist);
                }
            }
            if (categoryCheckedListBox.CheckedIndices.Count > 0)
            {
                sb.Append(" AND sl.Idcategory IN (:categories)");
                var clist = (from object cat in categoryCheckedListBox.CheckedIndices select ((int) cat + 1).ToString(CultureInfo.InvariantCulture)).ToList();
                pars.Add("categories", clist);
            }
            if (accessCheckedListBox.CheckedIndices.Count > 0)
            {
                sb.Append(" AND sl.Idaccess IN (:access)");
                var alist = (from object acc in accessCheckedListBox.CheckedIndices select ((int) acc + 1).ToString(CultureInfo.InvariantCulture)).ToList();
                pars.Add("access", alist);
            }
            dt1 = startDateTimePicker.Value;
            dt2 = endDateTimePicker.Value;
            return sb.ToString();
        }

        private string GetCount()
        {
            var check = DBwork.GetOptionValue(Server.ServerLogLastRecordsCountOptionName);
            if (check.Contains("err:"))
                MessageBox.Show(Main.Rm.GetString("NoOptionInDB") + @".");
            else
                return check;
            return "500";
        }

        private void SaveCount()
        {
            var check = DBwork.AddOrSetOptionValue(Server.ServerLogLastRecordsCountOptionName, countValue.Text);
            if (check.Contains("err:"))
                MessageBox.Show(Main.Rm.GetString("CanNotSaveOptionValueInDB"));
        }

        private void refreshToolStripMenuItem_Click_1(object sender, EventArgs e)
        {
            SaveCount();
            RefreshList();
        }

        private void CheckBox_CheckedChanged(object sender, EventArgs e)
        {
            var box = ((CheckBox) sender);
            var str = "";
            if (box.CheckState == CheckState.Checked)
            {
                box.Text = Main.Rm.GetString("SearchConditionExact");
                str = _boxChecked;
            }
            else
                if (box.CheckState == CheckState.Unchecked)
                {
                    box.Text = Main.Rm.GetString("SearchConditionLike");
                    str = _boxUnchecked;
                }
            _checkBoxTip.SetToolTip(box, str);
        }

        private void serverLogList_ColumnClick(object sender, ColumnClickEventArgs e)
        {
            serverLogList.Columns[_preColumn].ImageIndex = 0;
            if (_preColumn == e.Column)
                _ascSort = !_ascSort;
            _preColumn = e.Column;
            serverLogList.Columns[e.Column].ImageIndex = _ascSort ? 1: 2;
            serverLogList.ListViewItemSorter = new ListViewItemComparer(e.Column, _ascSort);
        }

        private void CheckBox_MouseEnter(object sender, EventArgs e)
        {
            var cb = (CheckBox) sender;
            var str = "";
            if (cb.CheckState == CheckState.Checked)
                str = _boxChecked;
            else if (cb.CheckState == CheckState.Unchecked)
                str = _boxUnchecked;
            _checkBoxTip.InitialDelay = 700;
            _checkBoxTip.RemoveAll();
            _checkBoxTip.SetToolTip(cb, str);
        }

        private void autoUpdateBox_CheckedChanged(object sender, EventArgs e)
        {
            var box = sender as CheckBox;
            var check = DBwork.AddOrSetOptionValue(AutoUpdateServerLogOption, box.Checked.ToString());
            if (check != "ok")
                MessageBox.Show(Main.Rm.GetString("CanNotSaveOptionValueInDB"), Main.Rm.GetString("Warning"), MessageBoxButtons.OK, MessageBoxIcon.Warning);
            if (box.Checked)
            {
                EnableTimer(_listUpdateTimer);
            }
            else
            {
                DisableTimer(_listUpdateTimer);
            }
        }

        private static void EnableTimer(Timer tim)
        {
            tim.Change(1000, Timeout.Infinite);
        }

        private static void DisableTimer(Timer tim)
        {
            tim.Change(Timeout.Infinite, Timeout.Infinite);
        }
    }

    class ListViewItemComparer : IComparer
    {
        private readonly int _col;
        private readonly bool _comp;
        public ListViewItemComparer(int column, bool asc)
        {
            /*if (column == 0)
                col = 5;
            else*/
            _comp = asc;
            _col = column;

        }
        public int Compare(object x, object y)
        {
            int ret;
            DateTime dt1, dt2;
            var a = ((ListViewItem) x).SubItems[_col].Text;
            var b = ((ListViewItem) y).SubItems[_col].Text;
            //--------------------------Сортировка по столбцам, содержащим дату
            if (DateTime.TryParseExact(((ListViewItem)x).SubItems[_col].Text, "dd.MM/HH:mm", CultureInfo.InvariantCulture, DateTimeStyles.None, out dt1))
            {
                if (b == "Нет данных")
                {
                    if (!_comp)
                        dt2 = DateTime.ParseExact("01.01/00:00", "dd.MM/HH:mm", CultureInfo.InvariantCulture);
                    else
                        dt2 = DateTime.ParseExact("31.12/00:00", "dd.MM/HH:mm", CultureInfo.InvariantCulture);
                }
                else
                    dt2 = DateTime.ParseExact(b, "dd.MM/HH:mm", CultureInfo.InvariantCulture);
                ret = DateTime.Compare(dt1, dt2);
            }
            else if (a == "Нет данных")
            {
                if (!_comp)
                    dt1 = DateTime.ParseExact("01.01/00:00", "dd.MM/HH:mm", CultureInfo.InvariantCulture);
                else
                    dt1 = DateTime.ParseExact("31.12/00:00", "dd.MM/HH:mm", CultureInfo.InvariantCulture);
                if (b == "Нет данных")
                    dt2 = DateTime.ParseExact("01.01/00:00", "dd.MM/HH:mm", CultureInfo.InvariantCulture);
                else
                    dt2 = DateTime.ParseExact(b, "dd.MM/HH:mm", CultureInfo.InvariantCulture);
                ret = DateTime.Compare(dt1, dt2);
            }
            //--------------------------
            else
                ret = String.CompareOrdinal(a, b);
            if (!_comp)
                ret *= -1;
            return ret;
        }
    }
}
